/*
 * Copyright (C) 2005 - 2013 MaNGOS <http://www.getmangos.com/>
 *
 * Copyright (C) 2008 - 2013 Trinity <http://www.trinitycore.org/>
 *
 * Copyright (C) 2010 - 2013 ProjectSkyfire <http://www.projectskyfire.org/>
 *
 * Copyright (C) 2011 - 2013 ArkCORE <http://www.arkania.net/>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 */

#ifndef ARKCORECORE_CREATURE_H
#define ARKCORECORE_CREATURE_H

#include "Common.h"
#include "Unit.h"
#include "UpdateMask.h"
#include "ItemPrototype.h"
#include "LootMgr.h"
#include "DatabaseEnv.h"
#include "Cell.h"

#include <list>

struct SpellEntry;

class CreatureAI;
class Quest;
class Player;
class WorldSession;
class CreatureGroup;

enum CreatureFlagsExtra
{
    CREATURE_FLAG_EXTRA_INSTANCE_BIND = 0x00000001,          // creature kill bind instance with killer and killer's group
    CREATURE_FLAG_EXTRA_CIVILIAN = 0x00000002,          // not aggro (ignore faction/reputation hostility)
    CREATURE_FLAG_EXTRA_NO_PARRY = 0x00000004,          // creature can't parry
    CREATURE_FLAG_EXTRA_NO_PARRY_HASTEN = 0x00000008,          // creature can't counter-attack at parry
    CREATURE_FLAG_EXTRA_NO_BLOCK = 0x00000010,          // creature can't block
    CREATURE_FLAG_EXTRA_NO_CRUSH = 0x00000020,          // creature can't do crush attacks
    CREATURE_FLAG_EXTRA_NO_XP_AT_KILL = 0x00000040,          // creature kill not provide XP
    CREATURE_FLAG_EXTRA_TRIGGER = 0x00000080,          // trigger creature
    CREATURE_FLAG_EXTRA_NO_TAUNT = 0x00000100,          // creature is immune to taunt auras and effect attack me
    CREATURE_FLAG_EXTRA_WORLDEVENT = 0x00004000,          // custom flag for world event creatures (left room for merging)
    CREATURE_FLAG_EXTRA_GUARD = 0x00008000,          // Creature is guard
    CREATURE_FLAG_EXTRA_NO_CRIT = 0x00020000,          // creature can't do critical strikes
    CREATURE_FLAG_EXTRA_NO_SKILLGAIN = 0x00040000,          // creature won't increase weapon skills
    CREATURE_FLAG_EXTRA_TAUNT_DIMINISH = 0x00080000,          // Taunt is a subject to diminishing returns on this creautre
    CREATURE_FLAG_EXTRA_ALL_DIMINISH = 0x00100000,          // Creature is subject to all diminishing returns as player are
    CREATURE_FLAG_EXTRA_DUNGEON_BOSS = 0x10000000,
// creature is a dungeon boss (SET DYNAMICALLY, DO NOT ADD IN DB)
};

#define CREATURE_FLAG_EXTRA_DB_ALLOWED (CREATURE_FLAG_EXTRA_INSTANCE_BIND | CREATURE_FLAG_EXTRA_CIVILIAN | \
    CREATURE_FLAG_EXTRA_NO_PARRY | CREATURE_FLAG_EXTRA_NO_PARRY_HASTEN | CREATURE_FLAG_EXTRA_NO_BLOCK | \
    CREATURE_FLAG_EXTRA_NO_CRUSH | CREATURE_FLAG_EXTRA_NO_XP_AT_KILL | CREATURE_FLAG_EXTRA_TRIGGER | \
    CREATURE_FLAG_EXTRA_NO_TAUNT | CREATURE_FLAG_EXTRA_WORLDEVENT | CREATURE_FLAG_EXTRA_NO_CRIT | \
    CREATURE_FLAG_EXTRA_NO_SKILLGAIN | CREATURE_FLAG_EXTRA_TAUNT_DIMINISH | CREATURE_FLAG_EXTRA_ALL_DIMINISH | \
    CREATURE_FLAG_EXTRA_GUARD)

// GCC have alternative #pragma pack(N) syntax and old gcc version not support pack(push, N), also any gcc version not support it at some platform
#if defined(__GNUC__)
#pragma pack(1)
#else
#pragma pack(push, 1)
#endif

#define MAX_KILL_CREDIT 2
#define CREATURE_REGEN_INTERVAL 2 * IN_MILLISECONDS

#define MAX_CREATURE_QUEST_ITEMS 6

// from `creature_template` table
struct CreatureInfo
{
    uint32 Entry;
    uint32 DifficultyEntry[MAX_DIFFICULTY - 1];
    uint32 KillCredit[MAX_KILL_CREDIT];
    uint32 Modelid1;
    uint32 Modelid2;
    uint32 Modelid3;
    uint32 Modelid4;
    char* Name;
    char* SubName;
    char* IconName;
    uint32 GossipMenuId;
    uint8 minlevel;
    uint8 maxlevel;
    uint32 expansion;
    uint32 faction_A;
    uint32 faction_H;
    uint32 npcflag;
    float speed_walk;
    float speed_run;
    float scale;
    uint32 rank;
    float mindmg;
    float maxdmg;
    uint32 dmgschool;
    uint32 attackpower;
    float dmg_multiplier;
    uint32 baseattacktime;
    uint32 rangeattacktime;
    uint32 unit_class;          // enum Classes. Note only 4 classes are known for creatures.
    uint32 unit_flags;          // enum UnitFlags mask values
    uint32 dynamicflags;
    uint32 family;          // enum CreatureFamily values (optional)
    uint32 trainer_type;
    uint32 trainer_spell;
    uint32 trainer_class;
    uint32 trainer_race;
    float minrangedmg;
    float maxrangedmg;
    uint32 rangedattackpower;
    uint32 type;          // enum CreatureType values
    uint32 type_flags;          // enum CreatureTypeFlags mask values
    uint32 lootid;
    uint32 pickpocketLootId;
    uint32 SkinLootId;
    int32 resistance1;
    int32 resistance2;
    int32 resistance3;
    int32 resistance4;
    int32 resistance5;
    int32 resistance6;
    uint32 spells[CREATURE_MAX_SPELLS];
    uint32 PetSpellDataId;
    uint32 VehicleId;
    uint32 mingold;
    uint32 maxgold;
    char const* AIName;
    uint32 MovementType;
    uint32 InhabitType;
    float ModHealth;
    float ModMana;
    float ModArmor;
    bool RacialLeader;
    uint32 questItems[MAX_CREATURE_QUEST_ITEMS];
    uint32 movementId;
    bool RegenHealth;
    uint32 equipmentId;
    uint32 MechanicImmuneMask;
    uint32 flags_extra;
    uint32 ScriptID;
    uint32 GetRandomValidModelId () const;
    uint32 GetFirstValidModelId () const;

    // helpers
    SkillType GetRequiredLootSkill () const
    {
        if (type_flags & CREATURE_TYPEFLAGS_HERBLOOT)
            return SKILL_HERBALISM;
        else if (type_flags & CREATURE_TYPEFLAGS_MININGLOOT)
            return SKILL_MINING;
        else if (type_flags & CREATURE_TYPEFLAGS_ENGINEERLOOT)
            return SKILL_ENGINEERING;
        else
            return SKILL_SKINNING;          // normal case
    }

    bool isTameable (bool exotic) const
    {
        if (type != CREATURE_TYPE_BEAST || family == 0 || (type_flags & CREATURE_TYPEFLAGS_TAMEABLE) == 0)
            return false;

        // if can tame exotic then can tame any temable
        return exotic || (type_flags & CREATURE_TYPEFLAGS_EXOTIC) == 0;
    }
};

// Represents max amount of expansions.
// TODO: Add MAX_EXPANSION constant.
#define MAX_CREATURE_BASE_HP 4

// Defines base stats for creatures (used to calculate HP/mana/armor).
struct CreatureBaseStats
{
    uint32 BaseHealth[MAX_CREATURE_BASE_HP];
    uint32 BaseMana;
    uint32 BaseArmor;

    // Helpers

    uint32 GenerateHealth (CreatureInfo const* info) const
    {
        return uint32((BaseHealth[info->expansion] * info->ModHealth) + 0.5f);
    }

    uint32 GenerateMana (CreatureInfo const* info) const
    {
        // Mana can be 0.
        if (!BaseMana)
            return 0;

        return uint32((BaseMana * info->ModMana) + 0.5f);
    }

    uint32 GenerateArmor (CreatureInfo const* info) const
    {
        return uint32((BaseArmor * info->ModArmor) + 0.5f);
    }

    static CreatureBaseStats const* GetBaseStats (uint8 level, uint8 unitClass);
};

typedef UNORDERED_MAP<uint16, CreatureBaseStats> CreatureBaseStatsMap;

struct CreatureLocale
{
    StringVector Name;
    StringVector SubName;
};

struct GossipMenuItemsLocale
{
    StringVector OptionText;
    StringVector BoxText;
};

struct PointOfInterestLocale
{
    StringVector IconName;
};

struct EquipmentInfo
{
    uint32 entry;
    uint32 equipentry[3];
};

// from `creature` table
struct CreatureData
{
    explicit CreatureData () :
            dbData(true)
    {
    }
    uint32 id;          // entry in creature_template
    uint16 mapid;
    uint16 phaseMask;
    uint32 displayid;
    int32 equipmentId;
    float posX;
    float posY;
    float posZ;
    float orientation;
    uint32 spawntimesecs;
    float spawndist;
    uint32 currentwaypoint;
    uint32 curhealth;
    uint32 curmana;
    bool is_dead;
    uint8 movementType;
    uint8 spawnMask;
    uint32 npcflag;
    uint32 unit_flags;          // enum UnitFlags mask values
    uint32 dynamicflags;
    bool dbData;
};

struct CreatureDataAddonAura
{
    uint32 spell_id;
    uint8 effectMask;
};

// from `creature_addon` table
struct CreatureDataAddon
{
    uint32 guidOrEntry;
    uint32 path_id;
    uint32 mount;
    uint32 bytes1;
    uint32 bytes2;
    uint32 emote;
    CreatureDataAddonAura const* auras;          // loaded as char* "spell1 eff1 spell2 eff2 ... "
};

struct CreatureModelInfo
{
    uint32 modelid;
    float bounding_radius;
    float combat_reach;
    uint8 gender;
    uint32 modelid_other_gender;
};

enum InhabitTypeValues
{
    INHABIT_GROUND = 1, INHABIT_WATER = 2, INHABIT_AIR = 4, INHABIT_ANYWHERE = INHABIT_GROUND | INHABIT_WATER | INHABIT_AIR
};

// Enums used by StringTextData::Type (CreatureEventAI)
enum ChatType
{
    CHAT_TYPE_SAY = 0, CHAT_TYPE_YELL = 1, CHAT_TYPE_TEXT_EMOTE = 2, CHAT_TYPE_BOSS_EMOTE = 3, CHAT_TYPE_WHISPER = 4, CHAT_TYPE_BOSS_WHISPER = 5, CHAT_TYPE_ZONE_YELL = 6, CHAT_TYPE_END = 255
};

// GCC have alternative #pragma pack() syntax and old gcc version not support pack(pop), also any gcc version not support it at some platform
#if defined(__GNUC__)
#pragma pack()
#else
#pragma pack(pop)
#endif

// Vendors
struct VendorItem
{
    VendorItem (uint32 _item, int32 _maxcount, uint32 _incrtime, uint32 _ExtendedCost) :
            item(_item), maxcount(_maxcount), incrtime(_incrtime), ExtendedCost(_ExtendedCost)
    {
    }

    uint32 item;
    uint32 maxcount;          // 0 for infinity item amount
    uint32 incrtime;          // time for restore items amount if maxcount != 0
    uint32 ExtendedCost;

    //helpers
    bool IsGoldRequired (ItemPrototype const* pProto) const
    {
        return pProto->Flags2 & ITEM_FLAGS_EXTRA_EXT_COST_REQUIRES_GOLD || !ExtendedCost;
    }
};
typedef std::vector<VendorItem*> VendorItemList;

struct VendorItemData
{
    VendorItemList m_items;

    VendorItem* GetItem (uint32 slot) const
    {
        if (slot >= m_items.size())
            return NULL;
        return m_items[slot];
    }
    bool Empty () const
    {
        return m_items.empty();
    }
    uint32 GetItemCount () const
    {
        return m_items.size();
    }
    void AddItem (uint32 item, int32 maxcount, uint32 ptime, uint32 ExtendedCost)
    {
        m_items.push_back(new VendorItem(item, maxcount, ptime, ExtendedCost));
    }
    bool RemoveItem (uint32 item_id);
    VendorItem const* FindItemCostPair (uint32 item_id, uint32 extendedCost) const;
    void Clear ()
    {
        for (VendorItemList::const_iterator itr = m_items.begin(); itr != m_items.end(); ++itr)
            delete (*itr);
        m_items.clear();
    }
};

struct VendorItemCount
{
    explicit VendorItemCount (uint32 _item, uint32 _count) :
            itemId(_item), count(_count), lastIncrementTime(time(NULL))
    {
    }

    uint32 itemId;
    uint32 count;
    time_t lastIncrementTime;
};

typedef std::list<VendorItemCount> VendorItemCounts;

struct TrainerSpell
{
    TrainerSpell () :
            spell(0), spellCost(0), reqSkill(0), reqSkillValue(0), reqLevel(0), KillCredit(0)
    {
        for (uint8 i = 0; i < MAX_SPELL_EFFECTS; ++i)
            learnedSpell[i] = 0;
    }

    uint32 spell;
    uint32 spellCost;
    uint32 reqSkill;
    uint32 reqSkillValue;
    uint32 reqLevel;
    uint32 KillCredit;
    uint32 learnedSpell[3];

    // helpers
    bool IsCastable () const
    {
        return learnedSpell[0] != spell;
    }
};

typedef UNORDERED_MAP<uint32 /*spellid*/, TrainerSpell> TrainerSpellMap;

struct TrainerSpellData
{
    TrainerSpellData () :
            trainerType(0)
    {
    }
    ~TrainerSpellData ()
    {
        spellList.clear();
    }

    TrainerSpellMap spellList;
    uint32 trainerType;          // trainer type based at trainer spells, can be different from creature_template value.
                                 // req. for correct show non-prof. trainers like weaponmaster, allowed values 0 and 2.
    TrainerSpell const* Find (uint32 spell_id) const;
};

typedef std::map<uint32, time_t> CreatureSpellCooldowns;

// max different by z coordinate for creature aggro reaction
#define CREATURE_Z_ATTACK_RANGE 3

#define MAX_VENDOR_ITEMS 300                                // Limitation raised in 4.x.x item count in SMSG_LIST_INVENTORY
class Creature: public Unit, public GridObject<Creature>
{
public:

    explicit Creature ();
    virtual ~Creature ();

    void AddToWorld ();
    void RemoveFromWorld ();

    void DisappearAndDie ();

    bool Create (uint32 guidlow, Map *map, uint32 phaseMask, uint32 Entry, uint32 vehId, uint32 team, float x, float y, float z, float ang, const CreatureData *data = NULL);
    bool LoadCreaturesAddon (bool reload = false);
    void SelectLevel (const CreatureInfo *cinfo);
    void LoadEquipment (uint32 equip_entry, bool force = false);

    uint32 GetDBTableGUIDLow () const
    {
        return m_DBTableGuid;
    }
    char const* GetSubName () const
    {
        return GetCreatureInfo()->SubName;
    }

    void Update (uint32 time);          // overwrited Unit::Update
    void GetRespawnCoord (float &x, float &y, float &z, float* ori = NULL, float* dist = NULL) const;
    uint32 GetEquipmentId () const
    {
        return GetCreatureInfo()->equipmentId;
    }

    void SetCorpseDelay (uint32 delay)
    {
        m_corpseDelay = delay;
    }
    uint32 GetCorpseDelay () const
    {
        return m_corpseDelay;
    }
    bool isRacialLeader () const
    {
        return GetCreatureInfo()->RacialLeader;
    }
    bool isCivilian () const
    {
        return GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_CIVILIAN;
    }
    bool isTrigger () const
    {
        return GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_TRIGGER;
    }
    bool isGuard () const
    {
        return GetCreatureInfo()->flags_extra & CREATURE_FLAG_EXTRA_GUARD;
    }
    bool canWalk () const
    {
        return GetCreatureInfo()->InhabitType & INHABIT_GROUND;
    }
    bool canSwim () const
    {
        return GetCreatureInfo()->InhabitType & INHABIT_WATER;
    }
    //bool canFly()  const { return GetCreatureInfo()->InhabitType & INHABIT_AIR; }

    void SetReactState (ReactStates st)
    {
        m_reactState = st;
    }
    ReactStates GetReactState ()
    {
        return m_reactState;
    }
    bool HasReactState (ReactStates state) const
    {
        return (m_reactState == state);
    }
    void InitializeReactState ()
    {
        if (isTotem() || isTrigger() || GetCreatureType() == CREATURE_TYPE_CRITTER || isSpiritService())
            SetReactState(REACT_PASSIVE);
        else
            SetReactState(REACT_AGGRESSIVE);
        /*else if (isCivilian())
         SetReactState(REACT_DEFENSIVE);*/;
    }

    ///// TODO RENAME THIS!!!!!
    bool isCanTrainingOf (Player* player, bool msg) const;
    bool isCanInteractWithBattleMaster (Player* player, bool msg) const;
    bool isCanTrainingAndResetTalentsOf (Player* pPlayer) const;
    bool canCreatureAttack (Unit const *pVictim, bool force = true) const;
    bool IsImmunedToSpell (SpellEntry const* spellInfo);
    // redefine Unit::IsImmunedToSpell
    bool IsImmunedToSpellEffect (SpellEntry const* spellInfo, uint32 index) const;
    // redefine Unit::IsImmunedToSpellEffect
    bool isElite () const
    {
        if (isPet())
            return false;

        uint32 rank = GetCreatureInfo()->rank;
        return rank != CREATURE_ELITE_NORMAL && rank != CREATURE_ELITE_RARE;
    }

    bool isWorldBoss () const
    {
        if (isPet())
            return false;

        return GetCreatureInfo()->rank == CREATURE_ELITE_WORLDBOSS;
    }

    bool IsDungeonBoss () const;

    uint8 getLevelForTarget (WorldObject const* target) const;          // overwrite Unit::getLevelForTarget for boss level support

    bool IsInEvadeMode () const
    {
        return HasUnitState(UNIT_STAT_EVADE);
    }

    bool AIM_Initialize (CreatureAI* ai = NULL);
    void Motion_Initialize ();

    bool SetWalk (bool enable);
    bool SetLevitate (bool enable);

    void AI_SendMoveToPacket (float x, float y, float z, uint32 time, uint32 MovementFlags, uint8 type);
    CreatureAI * AI () const
    {
        return (CreatureAI*) i_AI;
    }

    uint32 GetShieldBlockValue () const          //dunno mob block value
    {
        return (getLevel() / 2 + uint32(GetStat(STAT_STRENGTH) / 20));
    }

    SpellSchoolMask GetMeleeDamageSchoolMask () const
    {
        return m_meleeDamageSchoolMask;
    }
    void SetMeleeDamageSchool (SpellSchools school)
    {
        m_meleeDamageSchoolMask = SpellSchoolMask(1 << school);
    }

    void _AddCreatureSpellCooldown (uint32 spell_id, time_t end_time);
    void _AddCreatureCategoryCooldown (uint32 category, time_t apply_time);
    void AddCreatureSpellCooldown (uint32 spellid);
    bool HasSpellCooldown (uint32 spell_id) const;
    bool HasCategoryCooldown (uint32 spell_id) const;

    bool HasSpell (uint32 spellID) const;

    bool UpdateEntry (uint32 entry, uint32 team = ALLIANCE, const CreatureData* data = NULL);
    bool UpdateStats (Stats stat);
    bool UpdateAllStats ();
    void UpdateResistances (uint32 school);
    void UpdateArmor ();
    void UpdateMaxHealth ();
    void UpdateMaxPower (Powers power);
    void UpdateAttackPowerAndDamage (bool ranged = false);
    void UpdateDamagePhysical (WeaponAttackType attType);
    uint32 GetCurrentEquipmentId ()
    {
        return m_equipmentId;
    }
    void SetCurrentEquipmentId (uint32 entry)
    {
        m_equipmentId = entry;
    }
    float GetSpellDamageMod (int32 Rank);

    VendorItemData const* GetVendorItems () const;
    uint32 GetVendorItemCurrentCount (VendorItem const* vItem);
    uint32 UpdateVendorItemCurrentCount (VendorItem const* vItem, uint32 used_count);

    TrainerSpellData const* GetTrainerSpells () const;

    CreatureInfo const *GetCreatureInfo () const
    {
        return m_creatureInfo;
    }
    CreatureData const *GetCreatureData () const
    {
        return m_creatureData;
    }
    CreatureDataAddon const* GetCreatureAddon () const;

    std::string GetAIName () const;
    std::string GetScriptName () const;
    uint32 GetScriptId () const;

    void Say (int32 textId, uint32 language, uint64 TargetGuid)
    {
        MonsterSay(textId, language, TargetGuid);
    }
    void Yell (int32 textId, uint32 language, uint64 TargetGuid)
    {
        MonsterYell(textId, language, TargetGuid);
    }
    void TextEmote (int32 textId, uint64 TargetGuid, bool IsBossEmote = false)
    {
        MonsterTextEmote(textId, TargetGuid, IsBossEmote);
    }
    void Whisper (int32 textId, uint64 receiver, bool IsBossWhisper = false)
    {
        MonsterWhisper(textId, receiver, IsBossWhisper);
    }
    void YellToZone (int32 textId, uint32 language, uint64 TargetGuid)
    {
        MonsterYellToZone(textId, language, TargetGuid);
    }

    // overwrite WorldObject function for proper name localization
    const char* GetNameForLocaleIdx (LocaleConstant locale_idx) const;

    void setDeathState (DeathState s);          // overwrite virtual Unit::setDeathState
    bool FallGround ();

    bool LoadFromDB (uint32 guid, Map *map);
    void SaveToDB ();
    // overwrited in Pet
    virtual void SaveToDB (uint32 mapid, uint8 spawnMask, uint32 phaseMask);
    virtual void DeleteFromDB ();          // overwrited in Pet

    Loot loot;
    bool lootForPickPocketed;
    bool lootForBody;
    Player *GetLootRecipient () const;
    Group *GetLootRecipientGroup () const;
    bool hasLootRecipient () const
    {
        return m_lootRecipient || m_lootRecipientGroup;
    }
    bool isTappedBy (Player *player) const;          // return true if the creature is tapped by the player or a member of his party.

    void SetLootRecipient (Unit* unit);
    void AllLootRemovedFromCorpse ();

    uint16 GetLootMode ()
    {
        return m_LootMode;
    }
    bool HasLootMode (uint16 lootMode)
    {
        return m_LootMode & lootMode;
    }
    void SetLootMode (uint16 lootMode)
    {
        m_LootMode = lootMode;
    }
    void AddLootMode (uint16 lootMode)
    {
        m_LootMode |= lootMode;
    }
    void RemoveLootMode (uint16 lootMode)
    {
        m_LootMode &= ~lootMode;
    }
    void ResetLootMode ()
    {
        m_LootMode = LOOT_MODE_DEFAULT;
    }

    SpellEntry const *reachWithSpellAttack (Unit *pVictim);
    SpellEntry const *reachWithSpellCure (Unit *pVictim);

    uint32 m_spells[CREATURE_MAX_SPELLS];
    CreatureSpellCooldowns m_CreatureSpellCooldowns;
    CreatureSpellCooldowns m_CreatureCategoryCooldowns;
    uint32 m_GlobalCooldown;

    bool canStartAttack (Unit const* u, bool force) const;
    float GetAttackDistance (Unit const* pl) const;

    void SendAIReaction (AiReaction reactionType);

    Unit* SelectNearestTarget (float dist = 0) const;
    Unit* SelectNearestTargetInAttackDistance (float dist = 0) const;
    Player* SelectNearestPlayer (float distance = 0) const;

    void DoFleeToGetAssistance ();
    void CallForHelp (float fRadius);
    void CallAssistance ();
    void SetNoCallAssistance (bool val)
    {
        m_AlreadyCallAssistance = val;
    }
    void SetNoSearchAssistance (bool val)
    {
        m_AlreadySearchedAssistance = val;
    }
    bool HasSearchedAssistance ()
    {
        return m_AlreadySearchedAssistance;
    }
    bool CanAssistTo (const Unit* u, const Unit* enemy, bool checkfaction = true) const;
    bool _IsTargetAcceptable (const Unit* target) const;

    MovementGeneratorType GetDefaultMovementType () const
    {
        return m_defaultMovementType;
    }
    void SetDefaultMovementType (MovementGeneratorType mgt)
    {
        m_defaultMovementType = mgt;
    }

    // for use only in LoadHelper, Map::Add Map::CreatureCellRelocation
    Cell const& GetCurrentCell () const
    {
        return m_currentCell;
    }
    void SetCurrentCell (Cell const& cell)
    {
        m_currentCell = cell;
    }

    void RemoveCorpse (bool setSpawnTime = true);
    bool isDeadByDefault () const
    {
        return m_isDeadByDefault;
    }
    ;

    void ForcedDespawn (uint32 timeMSToDespawn = 0);
    void DespawnOrUnsummon (uint32 msTimeToDespawn = 0);

    time_t const& GetRespawnTime () const
    {
        return m_respawnTime;
    }
    time_t GetRespawnTimeEx () const;
    void SetRespawnTime (uint32 respawn)
    {
        m_respawnTime = respawn ? time(NULL) + respawn : 0;
    }
    void Respawn (bool force = false);
    void SaveRespawnTime ();

    uint32 GetRespawnDelay () const
    {
        return m_respawnDelay;
    }
    void SetRespawnDelay (uint32 delay)
    {
        m_respawnDelay = delay;
    }

    float GetRespawnRadius () const
    {
        return m_respawnradius;
    }
    void SetRespawnRadius (float dist)
    {
        m_respawnradius = dist;
    }

    uint32 m_groupLootTimer;          // (msecs)timer used for group loot
    uint32 lootingGroupLowGUID;          // used to find group which is looting corpse

    void SendZoneUnderAttackMessage (Player* attacker);

    void SetInCombatWithZone ();

    bool hasQuest (uint32 quest_id) const;
    bool hasInvolvedQuest (uint32 quest_id) const;

    bool isRegeneratingHealth ()
    {
        return m_regenHealth;
    }
    virtual uint8 GetPetAutoSpellSize () const
    {
        return MAX_SPELL_CHARM;
    }
    virtual uint32 GetPetAutoSpellOnPos (uint8 pos) const
    {
        if (pos >= MAX_SPELL_CHARM || m_charmInfo->GetCharmSpell(pos)->GetType() != ACT_ENABLED)
            return 0;
        else
            return m_charmInfo->GetCharmSpell(pos)->GetAction();
    }

    void SetHomePosition (float x, float y, float z, float o)
    {
        m_homePosition.Relocate(x, y, z, o);
    }
    void SetHomePosition (const Position &pos)
    {
        m_homePosition.Relocate(pos);
    }
    void GetHomePosition (float &x, float &y, float &z, float &ori)
    {
        m_homePosition.GetPosition(x, y, z, ori);
    }
    Position GetHomePosition ()
    {
        return m_homePosition;
    }

    uint32 GetGlobalCooldown () const
    {
        return m_GlobalCooldown;
    }

    uint32 GetWaypointPath ()
    {
        return m_path_id;
    }
    void LoadPath (uint32 pathid)
    {
        m_path_id = pathid;
    }

    uint32 GetCurrentWaypointID ()
    {
        return m_waypointID;
    }
    void UpdateWaypointID (uint32 wpID)
    {
        m_waypointID = wpID;
    }

    void SearchFormation ();
    CreatureGroup *GetFormation ()
    {
        return m_formation;
    }
    void SetFormation (CreatureGroup *formation)
    {
        m_formation = formation;
    }

    Unit *SelectVictim ();
    void SetDeadByDefault (bool death_state)
    {
        m_isDeadByDefault = death_state;
    }

    void SetDisableReputationGain (bool disable)
    {
        DisableReputationGain = disable;
    }
    bool IsReputationGainDisabled ()
    {
        return DisableReputationGain;
    }
    bool IsDamageEnoughForLootingAndReward () const
    {
        return m_PlayerDamageReq == 0;
    }
    void LowerPlayerDamageReq (uint32 unDamage)
    {
        if (m_PlayerDamageReq)
            m_PlayerDamageReq > unDamage ? m_PlayerDamageReq -= unDamage : m_PlayerDamageReq = 0;
    }
    void ResetPlayerDamageReq ()
    {
        m_PlayerDamageReq = GetHealth() / 2;
    }
    uint32 m_PlayerDamageReq;

    uint32 GetOriginalEntry () const
    {
        return m_originalEntry;
    }
    void SetOriginalEntry (uint32 entry)
    {
        m_originalEntry = entry;
    }

    static float _GetDamageMod (int32 Rank);

    float m_SightDistance, m_CombatDistance;

    void SetGUIDTransport (uint32 guid)
    {
        guid_transport = guid;
    }
    uint32 GetGUIDTransport ()
    {
        return guid_transport;
    }

    void FarTeleportTo (Map* map, float X, float Y, float Z, float O);
protected:
    bool CreateFromProto (uint32 guidlow, uint32 Entry, uint32 vehId, uint32 team, const CreatureData *data = NULL);
    bool InitEntry (uint32 entry, uint32 team = ALLIANCE, const CreatureData* data = NULL);

    // vendor items
    VendorItemCounts m_vendorItemCounts;

    static float _GetHealthMod (int32 Rank);

    uint32 m_lootMoney;
    uint64 m_lootRecipient;
    uint32 m_lootRecipientGroup;

    /// Timers
    time_t m_corpseRemoveTime;          // (msecs)timer for death or corpse disappearance
    time_t m_respawnTime;          // (secs) time of next respawn
    uint32 m_respawnDelay;          // (secs) delay between corpse disappearance and respawning
    uint32 m_corpseDelay;          // (secs) delay between death and corpse disappearance
    float m_respawnradius;

    ReactStates m_reactState;          // for AI, not charmInfo
    void RegenerateMana ();
    void RegenerateHealth ();
    void Regenerate (Powers power);
    MovementGeneratorType m_defaultMovementType;
    Cell m_currentCell;          // store current cell where creature listed
    uint32 m_DBTableGuid;          ///< For new or temporary creatures is 0 for saved it is lowguid
    uint32 m_equipmentId;

    bool m_AlreadyCallAssistance;
    bool m_AlreadySearchedAssistance;
    bool m_regenHealth;
    bool m_AI_locked;
    bool m_isDeadByDefault;

    SpellSchoolMask m_meleeDamageSchoolMask;
    uint32 m_originalEntry;

    Position m_homePosition;

    bool DisableReputationGain;

    CreatureInfo const* m_creatureInfo;          // in difficulty mode > 0 can different from ObjectMgr::GetCreatureTemplate(GetEntry())
    CreatureData const* m_creatureData;

    uint16 m_LootMode;          // bitmask, default LOOT_MODE_DEFAULT, determines what loot will be lootable
    uint32 guid_transport;

    bool isVisibleForInState (WorldObject const* seer) const;
    bool IsInvisibleDueToDespawn () const;
    bool canSeeAlways (WorldObject const* obj) const;
private:
    //WaypointMovementGenerator vars
    uint32 m_waypointID;
    uint32 m_path_id;

    //Formation var
    CreatureGroup *m_formation;
    bool TriggerJustRespawned;
};

class AssistDelayEvent: public BasicEvent
{
public:
    AssistDelayEvent (const uint64& victim, Unit& owner) :
            BasicEvent(), m_victim(victim), m_owner(owner)
    {
    }

    bool Execute (uint64 e_time, uint32 p_time);
    void AddAssistant (const uint64& guid)
    {
        m_assistants.push_back(guid);
    }
private:
    AssistDelayEvent ();

    uint64 m_victim;
    std::list<uint64> m_assistants;
    Unit& m_owner;
};

class ForcedDespawnDelayEvent: public BasicEvent
{
public:
    ForcedDespawnDelayEvent (Creature& owner) :
            BasicEvent(), m_owner(owner)
    {
    }
    bool Execute (uint64 e_time, uint32 p_time);

private:
    Creature& m_owner;
};

#endif
